package com.lin.benchmade.utils;

/**
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

public class SmallFloat {

	/** Converts a 32 bit float to an 8 bit float.
	 * <br>Values less than zero are all mapped to zero.
	 * <br>Values are truncated (rounded down) to the nearest 8 bit value.
	 * <br>Values between zero and the smallest representable value
	 *  are rounded up.
	 *
	 * @param f the 32 bit float to be converted to an 8 bit float (byte)
	 * @param numMantissaBits the number of mantissa bits to use in the byte, with the remainder to be used in the exponent
	 * @param zeroExp the zero-point in the range of exponent values
	 * @return the 8 bit float representation
	 */
	public static byte floatToByte(float f, int numMantissaBits, int zeroExp) {
		// Adjustment from a float zero exponent to our zero exponent,
		// shifted over to our exponent position.
		int fzero = (63 - zeroExp) << numMantissaBits;
		int bits = Float.floatToRawIntBits(f);
		int smallfloat = bits >> (24 - numMantissaBits);
		if (smallfloat <= fzero) {
			return (bits <= 0) ? (byte) 0 // negative numbers and zero both map
											// to 0 byte
					: (byte) 1; // underflow is mapped to smallest non-zero
								// number.
		} else if (smallfloat >= fzero + 0x100) {
			return -1; // overflow maps to largest number
		} else {
			return (byte) (smallfloat - fzero);
		}
	}

	/** Converts an 8 bit float to a 32 bit float. */
	public static float byteToFloat(byte b, int numMantissaBits, int zeroExp) {
		// on Java1.5 & 1.6 JVMs, prebuilding a decoding array and doing a
		// lookup
		// is only a little bit faster (anywhere from 0% to 7%)
		if (b == 0)
			return 0.0f;
		int bits = (b & 0xff) << (24 - numMantissaBits);
		bits += (63 - zeroExp) << 24;
		return Float.intBitsToFloat(bits);
	}

	//
	// Some specializations of the generic functions follow.
	// The generic functions are just as fast with current (1.5)
	// -server JVMs, but still slower with client JVMs.
	//

	/** floatToByte(b, mantissaBits=3, zeroExponent=15)
	 * <br>smallest non-zero value = 5.820766E-10
	 * <br>largest value = 7.5161928E9
	 * <br>epsilon = 0.125
	 */
	public static byte floatToByte315(float f) {
		int bits = Float.floatToRawIntBits(f);
		int smallfloat = bits >> (24 - 3);
		if (smallfloat <= ((63 - 15) << 3)) {
			return (bits <= 0) ? (byte) 0 : (byte) 1;
		}
		if (smallfloat >= ((63 - 15) << 3) + 0x100) {
			return -1;
		}
		return (byte) (smallfloat - ((63 - 15) << 3));
	}

	/** byteToFloat(b, mantissaBits=3, zeroExponent=15) */
	public static float byte315ToFloat(byte b) {
		// on Java1.5 & 1.6 JVMs, prebuilding a decoding array and doing a
		// lookup
		// is only a little bit faster (anywhere from 0% to 7%)
		if (b == 0)
			return 0.0f;
		int bits = (b & 0xff) << (24 - 3);
		bits += (63 - 15) << 24;
		return Float.intBitsToFloat(bits);
	}

	/** floatToByte(b, mantissaBits=5, zeroExponent=2)
	 * <br>smallest nonzero value = 0.033203125
	 * <br>largest value = 1984.0
	 * <br>epsilon = 0.03125
	 */
	public static byte floatToByte52(float f) {
		int bits = Float.floatToRawIntBits(f);
		int smallfloat = bits >> (24 - 5);
		if (smallfloat <= (63 - 2) << 5) {
			return (bits <= 0) ? (byte) 0 : (byte) 1;
		}
		if (smallfloat >= ((63 - 2) << 5) + 0x100) {
			return -1;
		}
		return (byte) (smallfloat - ((63 - 2) << 5));
	}

	/** byteToFloat(b, mantissaBits=5, zeroExponent=2) */
	public static float byte52ToFloat(byte b) {
		// on Java1.5 & 1.6 JVMs, prebuilding a decoding array and doing a
		// lookup
		// is only a little bit faster (anywhere from 0% to 7%)
		if (b == 0)
			return 0.0f;
		int bits = (b & 0xff) << (24 - 5);
		bits += (63 - 2) << 24;
		return Float.intBitsToFloat(bits);
	}
}
